#include <Application.h>

//using namespace tinyxml2;

Application *g_pApp = NULL;

Application::Application()
{
	g_pApp = this;
	m_bRunning = false;
	m_screenWidth = 1024;
	m_screenHeight = 768;
	m_colorDepth = 32;
	m_coreRefreshTime = 30;
	m_bFullscreen = false;
	m_language = "English";
};

bool Application::VInitialize(HINSTANCE hInstance, LPTSTR lpCmdLine, HWND hWnd)
{
	m_pGame = VCreateGame();
	if (!m_pGame)
	{
		MessageBox(hWnd, L"Error creating the Game", L"Error", MB_OK);
		return false;
	}

	if(!m_pGame->VPreload())
	{
		MessageBox(hWnd, L"Error preloading the Game", L"Error", MB_OK);
		return false;
	}

	if(!LoadStrings(m_language))
	{
		MessageBox(hWnd, L"Error loading Language File", L"Error", MB_OK);
		return false;
	}

	m_pEventMgr = ALE_NEW EventManager("App EventManager", true);
	if (!m_pEventMgr)
	{
		MessageBox(hWnd, L"Error creating the EventManager", L"Error", MB_OK);
		return false;
	}

	if(!LuaStateManager::Create())
	{
		MessageBox(hWnd, L"Error creating the LuaManager", L"Error", MB_OK);
		return false;
	}

	m_hInstance = hInstance;

	if (hWnd == NULL)
	{
		if(!CreateGameWindow())
		{
			MessageBox(m_hWnd, L"Error creating program window!", L"Error", MB_OK);
			return false;
		}
	}
	else
	{
		m_hWnd = hWnd;
	}

	m_pRenderer = ALE_NEW DXRenderer();
	if(!m_pRenderer->Init(m_hWnd, m_screenWidth, m_screenHeight, m_colorDepth, m_bFullscreen))
	{
		MessageBox(hWnd, L"Error creating Renderer", L"Error", MB_OK);
		return false;
	}

	m_pInput = ALE_NEW CInput(m_hWnd);
	if(!m_pInput)
	{
		MessageBox(hWnd, L"Error creating Input", L"Error", MB_OK);
		return false;
	}

	m_pAudio = ALE_NEW Audio();
	if(!m_pAudio->Init())
	{
		MessageBox(hWnd, L"Error creating Audio", L"Error", MB_OK);
		return false;
	}

	if(!m_pGame->VInit())
	{
		MessageBox(hWnd, L"Error initializing the Game", L"Error", MB_OK);
		return false;
	}

	m_coreTimer.reset();
	m_bRunning = true;

	return true;
}

void Application::VUpdate()
{
	m_pEventMgr->VUpdate(20);
	m_pAudio->Update();
	m_pInput->Update();
	m_pInput->SendEvents();

	if(m_pGame)
	{
		if (m_coreRefreshTime != 0 && m_coreTimer.stopwatch(m_coreRefreshTime))
			m_pGame->VUpdate(m_coreTimer.deltaTime());

		m_pGame->VRenderViews();
	}
}

void Application::VShutdown()
{
	m_bRunning = false;
	PostQuitMessage(0);
}

void Application::VClose()
{
	if(m_pAudio)
	{
		m_pAudio->StopAll();
		delete m_pAudio;
	}
	SAFE_DELETE(m_pInput);
	SAFE_DELETE(m_pRenderer);
	LuaStateManager::Destroy();
	SAFE_DELETE(m_pEventMgr);
	SAFE_DELETE(m_pGame);
}

void Application::RunMainLoop()
{
	MSG msg;
	while (m_bRunning)
	{
		while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		VUpdate();
	}
}

LRESULT WINAPI Application::WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch( msg )
	{
		case WM_QUIT:
		case WM_CLOSE:
		case WM_DESTROY:
			g_pApp->VShutdown();
			break;
	}
	return DefWindowProc( hWnd, msg, wParam, lParam );
}

bool Application::CreateGameWindow()
{
	RECT windowRect;
	windowRect.left = (long)0;
	windowRect.right = (long)m_screenWidth;
	windowRect.top = (long)0;
	windowRect.bottom = (long)m_screenHeight;

	WNDCLASSEX wc;
	wc.cbSize = sizeof(WNDCLASSEX);

	wc.style		 = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc   = (WNDPROC)WinProc;
	wc.cbClsExtra	 = 0;
	wc.cbWndExtra	 = 0;
	wc.hInstance	 = m_hInstance;
	wc.hIcon		 = NULL;
	wc.hCursor	   = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = NULL;
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = VGetGameTitle();
	wc.hIconSm	   = NULL;

	RegisterClassEx(&wc);

	DWORD dwStyle, dwExStyle;
	if (m_bFullscreen)
	{
		DEVMODE dm;
		memset(&dm, 0, sizeof(dm));
		dm.dmSize = sizeof(dm);
		dm.dmPelsWidth = m_screenWidth;
		dm.dmPelsHeight = m_screenHeight;
		dm.dmBitsPerPel = m_colorDepth;
		dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

		if (ChangeDisplaySettings(&dm, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) 
		{
			MessageBox(NULL, L"Display mode failed", NULL, MB_OK);
			m_bFullscreen = false;
		}

		dwStyle = WS_POPUP;
		dwExStyle = WS_EX_APPWINDOW;
		ShowCursor(FALSE);
	}
	else
	{
		dwStyle = WS_OVERLAPPEDWINDOW;
		dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
	}

	AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle);

	m_hWnd = CreateWindowEx( 0,
		VGetGameTitle(),								 //window class
		VGetGameTitle(),								 //title bar
		dwStyle | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,	  
		0, 0,											 //x,y coordinate
		windowRect.right - windowRect.left,			   //width of the window
		windowRect.bottom - windowRect.top,			   //height of the window
		0,											 //parent window
		0,											 //menu
		m_hInstance,									  //application instance
		0);	

	if (!m_hWnd)
	{
		return false;
	}

	//???
	int nCmdShow = 1;

	ShowWindow(m_hWnd, nCmdShow);
	UpdateWindow(m_hWnd);
	return true;

	return true;
}

bool Application::LoadStrings(std::string language)
{
	std::string languageFile = "Strings\\";
	languageFile += language;
	languageFile += ".xml";

	//TODO: loading from res

	tinyxml2::XMLDocument doc;
	if (doc.LoadFile(languageFile.c_str()) != tinyxml2::XML_NO_ERROR)
		return false;

	tinyxml2::XMLElement* pRoot = doc.RootElement();
	if (!pRoot)
		return false;

	for (tinyxml2::XMLElement* pElem = pRoot->FirstChildElement(); pElem;
		pElem = pElem->NextSiblingElement())
	{
		const char *pKey = pElem->Attribute("id");
		const char *pText = pElem->Attribute("value");
		if (pKey && pText)
		{
			wchar_t wideKey[64];
			wchar_t wideText[1024];

			//TODO: export in extra funtion
			MultiByteToWideChar( CP_ACP, 0, pKey, -1, wideKey, 64 );
			wideKey[64-1] = 0;
			MultiByteToWideChar( CP_ACP, 0, pText, -1, wideText, 1024 );
			wideText[1024-1] = 0;

			m_textResource[std::wstring(wideKey)] = std::wstring(wideText);
		}
	}

	return true;
}

std::wstring Application::GetString(std::wstring sID)
{
	auto localString = m_textResource.find(sID);
	if (localString == m_textResource.end())
	{
		return L"";
	}
	return localString->second;
}